﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
//using System.Data;
using System.Drawing;
using System.IO;
using System.Timers;
//using System.Linq;
using System.Runtime.InteropServices; 
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Windows.Forms;
//using System.Threading;
using System.Text.RegularExpressions;

namespace SerialCapture
{
    public partial class form_main : Form
    {
        public static string rootPath = Directory.GetCurrentDirectory();
        private static string configName = rootPath + "\\Config.dat";
        //private static string traceFolder = rootPath + "\\Trace\\";
        private string traceFolder;
        public  static Boolean on1sTimer;
        private long sizeLimit;
        public static Boolean traceFileAccessFlag;
        public  string traceFile;
        public  string startTime;
        public string stopTime;
        public  string endTime;
        public string currentTime;
        public string currentDate;

        private FileStream fs;
        private BinaryFormatter bf = new BinaryFormatter();
        private Config myConfig;
        private FileInfo fileInfoTraceFile;
        //private DateTime now;
        private System.Timers.Timer aTimer;
        private Log myLog;
        private int markerCount;

        private Boolean init_config_flag;
        private Boolean isRunning;
        private Boolean isStopped;
        private Boolean KPIFlag;

        private Serial objSerial;
        public form_main()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            if (!Directory.Exists(rootPath + "\\log"))
            {
                Directory.CreateDirectory(rootPath + "\\log");
            }
            myLog = new Log();
            isRunning = false;
            myLog.appendLogText("-----------------new life cycle of the program.--------------");
            myLog.appendLogText("");
            myLog.appendLogText("Start loading the Form. Log object successfully init.");

               //new changeFormButtonContent(this.activeSerial_changeContent);
            this.FormClosing += new FormClosingEventHandler(this.before_close);
            aTimer = new System.Timers.Timer();
                aTimer.Elapsed += new ElapsedEventHandler(TimeEvent);
                aTimer.Interval = 50;

            this.init_config_flag = false;
            this.isStopped = false;
            this.isRunning = false;
            this.markerCount = 1;

            traceFileAccessFlag = false;

            if (!File.Exists(configName))
            {
                MessageBox.Show("Configuration file not found. Use Default Settings.");
                myLog.appendLogText("config file not existed. use default setting. which is null...");
                myConfig = new Config();
                this.init_config_flag = false;
                this.sizeLimit = 30 * 1000 * 1000;
                myLog.appendLogText("set the trace file size limit as " + this.sizeLimit.ToString() + " bytes");
            }
            else {
                fs = new FileStream(configName, FileMode.OpenOrCreate);
                try
                {
                    myConfig = (Config)bf.Deserialize(fs);
                    //this one is for test, only 1kb. remove after debug done.
                    //this.sizeLimit = Convert.ToInt64(myConfig.myGenSettings.sizeLimit) * 1000;
                    this.sizeLimit = Convert.ToInt64(myConfig.myGenSettings.sizeLimit) * 1000 * 1000;
                    this.checkBox_KPI.Checked = myConfig.myGenSettings.KPIActive;
                    this.init_config_flag = true;
                    this.traceFile = myConfig.myGenSettings.traceFolder + "\\tempTraceFile.txt";
                    myLog.appendLogText("Load Config file OK. ");
                    //myLog.appendLogText("\t --Trace file length is: " + File.);
                    myLog.appendLogText("\t --size limit is " + this.sizeLimit.ToString() + " bytes");
                    myLog.appendLogText("\t --Trace file is " + this.traceFile);
                    myLog.appendLogText("\t --KPI Flag is " + this.myConfig.myGenSettings.KPIActive.ToString());
                    myLog.appendLogText("\t --Port is " + myConfig.myProject.mySerial.myName);
                }
                catch (Exception err)
                {
                    MessageBox.Show("Read config file failed: [" + err.Message + "].");
                    myLog.appendLogText("Read config file failed: [" + err.Message + "].");
                    this.init_config_flag = false;
                }
                finally {
                    if (fs != null)
                        fs.Close();
                    myLog.appendLogText("close the file handle of config file");
                }
            }
            
            //init content of components.
            if (this.init_config_flag) {
                if (File.Exists(this.traceFile)) {
                    DialogResult dr = MessageBox.Show("old trace file detected, recommended delete them?", "Old Trace Detected", MessageBoxButtons.YesNo);
                    if (dr == DialogResult.Yes) {
                        File.Delete(this.traceFile);
                    }
                
                }
            }
            
            init_serial_cbb_content();


            if (this.checkBox_KPI.Checked)
            {
                this.KPIFlag = true;
                myLog.appendLogText("KPI flag is checked. KPI analyze is enabled.");

            }
            else
            {
                this.KPIFlag = false;
            }
            //new the necessary object.
            objSerial = new Serial(this.KPIFlag);
            myLog.appendLogText("initialized the content in the UI.");
        }

        public void activeSerial_changeContent(string s)
        {
            this.button_set_marker.Text = s;
            this.button_set_marker.Refresh();
        }

        private void before_close(object sender, FormClosingEventArgs e) {
            if (isRunning) {
                MessageBox.Show("Please Exit current work first.");
                e.Cancel = true;
            }

            if (save_data_to_config())
            {
                myLog.appendLogText("save user data before exit the program OK.");
                myLog.appendLogText("program exit.");
                myLog.appendLogText("");
                //update status info
                //write down traces.
            }
            else
            {
                MessageBox.Show("Save Config file failed. Your change not saved.");
                //write down traces.
            }
        }

        private void cbb_serial_ports_drop_down(object sender, EventArgs e)
        {
            objSerial.refreshPorts();
            this.cbb_serial_ports.Items.Clear();
            foreach (string s in this.objSerial.strPorts) {
                this.cbb_serial_ports.Items.Add(s);
            }
        }

        private void init_serial_cbb_content() {
            foreach (SerialPortBaudRates br in Enum.GetValues(typeof(SerialPortBaudRates))) {
                this.cbb_baudrate.Items.Add(Convert.ToString(br));
            }

            foreach (SerialPortDatabits db in Enum.GetValues(typeof(SerialPortDatabits))) {
                this.cbb_data_bits.Items.Add(Convert.ToString(db));
            }

            foreach (System.IO.Ports.StopBits sb in Enum.GetValues(typeof(System.IO.Ports.StopBits))) {
                this.cbb_stop_bits.Items.Add(sb);
            }

            foreach (System.IO.Ports.Parity p in Enum.GetValues(typeof(System.IO.Ports.Parity))) {
                this.cbb_parity.Items.Add(p);
            }

            foreach (System.IO.Ports.Handshake hs in Enum.GetValues(typeof(System.IO.Ports.Handshake)))
            {
                this.cbb_flow_control.Items.Add(hs);
            }

            if (this.init_config_flag) {
                this.cbb_projects.Text = myConfig.myProject.name.ToString();
                this.cbb_serial_ports.Text = myConfig.myProject.mySerial.myName;
                this.cbb_data_bits.Text = Enum.GetName(typeof(SerialPortDatabits), myConfig.myProject.mySerial.myDataBits);
                this.cbb_baudrate.Text = myConfig.myProject.mySerial.myBaudRate.ToString();
                this.cbb_parity.Text = myConfig.myProject.mySerial.myParity.ToString();
                this.cbb_stop_bits.Text = myConfig.myProject.mySerial.myStopBits.ToString();
                this.cbb_flow_control.Text = myConfig.myProject.mySerial.myFlowControl.ToString();

                this.tb_trace_size.Text = myConfig.myGenSettings.sizeLimit.ToString();
                this.tb_trace_folder.Text = myConfig.myGenSettings.traceFolder.ToString();
            }
        }

        public void button_start_trace_Click(object sender, EventArgs e)
        {
            if (this.isRunning) {
                return;
            }

            //myLog.appendLogText("KPI State " + this.objSerial.activeSerial.KPICheck.ToString()); 

            if (this.tb_trace_folder.Text == "") {
                MessageBox.Show("no trace folder selected.");
                return;
            }
            this.isStopped = false;
            this.isRunning = true;
            this.traceFolder = myConfig.myGenSettings.traceFolder;
            traceFile = traceFolder + "\\tempTraceFile.txt";
            fileInfoTraceFile = new FileInfo(this.traceFile);
            this.button_start_trace.ForeColor = Color.Green;
            this.button_start_trace.Refresh();

            if (!Directory.Exists(traceFolder))
            {
                Directory.CreateDirectory(traceFolder);
            }
            
            if (!File.Exists(this.traceFile))
            {
                this.fileInfoTraceFile.Create().Close();
            }
            //this.now = DateTime.Now;
            this.startTime = DateTime.Now.ToString("[yy-MM-dd]_hh.mm.ss");
            //first we need to save the configuration.
            if (save_data_to_config())
            {
                //update status info
                //write down traces.
                myLog.appendLogText("Configurations saved.");
            }
            else { 
                //write down traces.
                myLog.appendLogText("Configuration failed to save",logFileTypeEnum.normal,logTypeEnum.ERROR);
                this.isStopped = true;
                this.isRunning = false;
                this.button_start_trace.ForeColor = Color.Black;
                this.button_start_trace.Refresh();
                return;
            }

            aTimer.Enabled = true;
            objSerial.KPICheck = this.KPIFlag;
            objSerial.setActivePort(myConfig.myProject.mySerial.myName,
                        myConfig.myProject.mySerial.myBaudRate,
                        myConfig.myProject.mySerial.myDataBits,
                        myConfig.myProject.mySerial.myStopBits,
                        myConfig.myProject.mySerial.myParity,
                        myConfig.myProject.mySerial.myFlowControl,
                        this.traceFile);
            //objSerial.activeSerial.KPICheck = this.KPIFlag;
            //anyway we will start the trace.

            //myLog.appendLogText("KPI obj activeSerial flag as " + objSerial.activeSerial.KPICheck.ToString());
            try
            {
                //            first we need to create the trace file.

                if (!objSerial.activeSerial.IsOpen)
                {
                    if (!objSerial.activeSerial.openSerialPort()) {
                        MessageBox.Show(objSerial.activeSerial.PortName + " open failed. Please view log for detailed info.");
                        aTimer.Enabled = false;
                        this.isStopped = true;
                        this.isRunning = false;
                        this.button_start_trace.ForeColor = Color.Black;
                        this.button_start_trace.Refresh();
                        return;
                    }
                }
                else {
                    MessageBox.Show(objSerial.activeSerial.PortName + " is already in use. Please Check.");
                    aTimer.Enabled = false;
                    this.isStopped = true;
                    this.isRunning = false;
                    this.button_start_trace.ForeColor = Color.Black;
                    this.button_start_trace.Refresh();
                    return;
                }
            }
            catch (Exception err) {
                //MessageBox.Show();
                //write down traces.
                MessageBox.Show(objSerial.activeSerial.PortName + " open failed: " + err.Message);
                aTimer.Enabled = false;
                this.isStopped = true;
                this.isRunning = false;
                return;
            }
        }

        private Boolean save_data_to_config() {
            try
            {
                myLog.appendLogText("start to save the user data into config file.");
                myConfig.myProject.mySerial.myBaudRate = (SerialPortBaudRates)Enum.Parse(typeof(SerialPortBaudRates), this.cbb_baudrate.SelectedItem.ToString());
                myConfig.myProject.mySerial.myDataBits = (SerialPortDatabits)Enum.Parse(typeof(SerialPortDatabits), this.cbb_data_bits.Text);
                myConfig.myProject.mySerial.myName = this.cbb_serial_ports.Text;
                myConfig.myProject.name = this.cbb_projects.Text.ToString();
                myConfig.myProject.mySerial.myStopBits = (System.IO.Ports.StopBits)Enum.Parse(typeof(System.IO.Ports.StopBits), this.cbb_stop_bits.SelectedIndex.ToString());
                myConfig.myProject.mySerial.myParity = (System.IO.Ports.Parity)Enum.Parse(typeof(System.IO.Ports.Parity), this.cbb_parity.SelectedIndex.ToString());
                myConfig.myProject.mySerial.myFlowControl = (System.IO.Ports.Handshake)Enum.Parse(typeof(System.IO.Ports.Handshake), this.cbb_flow_control.SelectedIndex.ToString());
                myConfig.myGenSettings.sizeLimit = Convert.ToInt16(this.tb_trace_size.Text);
                myConfig.myGenSettings.traceFolder = this.tb_trace_folder.Text;
                myConfig.myGenSettings.KPIActive = this.checkBox_KPI.Checked;
                File.Delete(configName);
                fs = new FileStream(configName, FileMode.OpenOrCreate);
                bf.Serialize(fs, myConfig);
                return true;
            }
            catch(Exception err)
            {
                //MessageBox.Show(err.Message);
                myLog.appendLogText("failed to save data into config file: [" + err.Message + "]");
                return false;
            }
            finally {
                if (fs != null)
                    fs.Close();
            }
        }

        private void button_change_trace_folder_Click(object sender, EventArgs e)
        {
            if (myConfig.myGenSettings.traceFolder != null)
            {
                this.folderBrowserDialog1.SelectedPath = myConfig.myGenSettings.traceFolder;
            }
            if (folderBrowserDialog1.ShowDialog() == DialogResult.OK) {
                myConfig.myGenSettings.traceFolder = folderBrowserDialog1.SelectedPath;
            }

            this.tb_trace_folder.Text = myConfig.myGenSettings.traceFolder.ToString();
        }

        private void TimeEvent(object source, ElapsedEventArgs e) {
            on1sTimer = true;
            FileInfo fi = new FileInfo(this.traceFile);
            long fileSize = fi.Length;
            //if (!traceFileAccessFlag) {
            if (fileSize > this.sizeLimit)
            {
                //check if the trace file is accessing.
                if (!traceFileAccessFlag)
                {
                    myLog.appendLogText("detected log file length too much, now start to move the file.");
                    //traceFileAccessFlag = true;
                    //this.stopTime = DateTime.Now.ToString("[yy-MM-dd]_hh.mm.ss");
                    //string targetFile = traceFolder + "Trace_" + myConfig.myProject.name + "_" + this.startTime + "_" + this.stopTime + ".txt";
                    //File.Copy(fi.FullName, targetFile,true);
                    //fi.Delete();
                    //fi.Create().Close();
                    //this.startTime = DateTime.Now.ToString("[yy-MM-dd]_hh.mm.ss");
                    //traceFileAccessFlag = false;

                    traceFileAccessFlag = true;
                    this.stopTime = DateTime.Now.ToString("[yy-MM-dd]_hh.mm.ss");
                    string targetFile = traceFolder + "\\Trace_" + myConfig.myProject.name + "_" + this.startTime + "_" + this.stopTime + ".txt";
                    fileInfoTraceFile.CopyTo(targetFile, true);
                    fileInfoTraceFile.Delete();
                    fileInfoTraceFile.Create().Close();
                    //fileInfoTraceFile.Create().Close();
                    this.startTime = DateTime.Now.ToString("[yy-MM-dd]_hh.mm.ss");
                    traceFileAccessFlag = false;



                }
            }
            else {
                fi = null;
            }
           // }
        }

        public void button_stop_Click(object sender, EventArgs e)
        {
            if (this.isStopped) {
                return;
            }

            this.markerCount = 1;
            this.button_set_marker.Text = "Set Marker " + this.markerCount.ToString();
             
            aTimer.Enabled = false;
            isRunning = false;
            this.button_start_trace.ForeColor = Color.Black;
            this.button_start_trace.Refresh();
            //after stop
            // close the serial port
            // free object objSerial.ActiveSerial
            // close the file handle to trace file.
            // copy the last file to target file.
            // delete src file?
            try
            {

                objSerial.activeSerial.Close();
 
                objSerial.activeSerial = null;

                if (!traceFileAccessFlag) {
                    traceFileAccessFlag = true;
                    this.stopTime = DateTime.Now.ToString("[yy-MM-dd]_hh.mm.ss");
                    string targetFile = traceFolder + "\\Trace_" + myConfig.myProject.name + "_" + this.startTime + "_" + this.stopTime + ".txt";
                    fileInfoTraceFile.CopyTo(targetFile, true);
                    fileInfoTraceFile.Delete();
                    //fileInfoTraceFile.Create().Close();
                    //this.startTime = this.now.ToString("[yy-MM-dd]_hh.mm.ss");
                    traceFileAccessFlag = false;
                }
                this.isStopped = true;
            }
            catch (Exception err) {
                MessageBox.Show(err.Message);
            }
        }

        private void button1_Click(object sender, EventArgs e)
        {

        }

        private void button_set_marker_Click(object sender, EventArgs e)
        {
            if (this.isRunning) {
                objSerial.activeSerial.marker = true;
                this.markerCount += 1;

                this.button_set_marker.Text = "Set Marker " + this.markerCount.ToString();
                this.button_set_marker.Refresh();
            }
        }

        private void buttonTest_Click(object sender, EventArgs e)
        {
            //string outResult;

            //=========================below is for test REGEX===================================
            //string deviceType;
            //Regex regAvailable = new Regex("\"available\":true");
            //Regex regContent = new Regex("\"content\":\"[a-z]+\"");
            //Regex regType = new Regex("\"type\":\"[a-z]+\"");

            //deviceType = "unknown device";
            //outResult = null;
            //if (regAvailable.IsMatch(this.textBox_test.Text)){
            //    if(regType.IsMatch(this.textBox_test.Text)){
            //        foreach (Match mar in regType.Matches(this.textBox_test.Text)){
            //            deviceType = mar.Groups[0].Value.Replace("\"", "").Split(':')[1];
            //        }
            //    }
            //    outResult = deviceType + " detected;";
            //    if (regContent.IsMatch(this.textBox_test.Text)) {
            //        //foreach (Match mar in regContent.Matches(this.textBox_test.Text)) {
            //        //    foreach (Group gp in mar.Groups) {
            //        //        outResult += gp.Value;
            //        //    }
            //        //}
            //        outResult += " Playable;";
            //    }
            //}

            //===================below is for test double value=======================
            //long t1 = 1234567890456;
            //double t2 = 100000.00;
            //outResult = (t1 / t2).ToString(".00");
            //MessageBox.Show(outResult);
        }

        private void checkBox_KPI_CheckedChanged(object sender, EventArgs e)
        {
            if (this.checkBox_KPI.Checked)
            {
                this.KPIFlag = true;
            }
            else
            {
                this.KPIFlag = false;
            }
        }

        private void button_serial_test_Click(object sender, EventArgs e)
        {
            save_data_to_config();

            mySerialPort testSerial = new mySerialPort(myConfig.myProject.mySerial.myName,
                        myConfig.myProject.mySerial.myBaudRate,
                        myConfig.myProject.mySerial.myDataBits,
                        myConfig.myProject.mySerial.myStopBits,
                        myConfig.myProject.mySerial.myParity,
                        myConfig.myProject.mySerial.myFlowControl);
            try
            {
                testSerial.Open();
                MessageBox.Show("Open Serial Port OK!");
                testSerial.Close();
            }
            catch (Exception err) {
                MessageBox.Show("Open Serial port " + testSerial.PortName + " failed: " + err.Message);
            }finally{
                testSerial = null;
            }
        }
    }
}
